package com.ruoyi.wms.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.constant.ServiceConstants;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.MapstructUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import com.ruoyi.common.satoken.utils.LoginHelper;
import com.ruoyi.wms.common.enu.PurchaseStatusEnum;
import com.ruoyi.wms.common.enu.ReceiptTypeEnum;
import com.ruoyi.wms.domain.bo.stock.PurchaseRequestDetailsBo;
import com.ruoyi.wms.domain.bo.stock.PurchaseRequestsBo;
import com.ruoyi.wms.domain.bo.stock.ReceiptOrderBo;
import com.ruoyi.wms.domain.bo.stock.ReceiptOrderDetailBo;
import com.ruoyi.wms.domain.entity.stock.PurchaseRequestDetails;
import com.ruoyi.wms.domain.entity.stock.PurchaseRequests;
import com.ruoyi.wms.domain.entity.stock.ReceiptOrder;
import com.ruoyi.wms.domain.entity.stock.ReceiptOrderDetail;
import com.ruoyi.wms.domain.vo.*;
import com.ruoyi.wms.mapper.*;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.lang3.RandomStringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 采购申请Service业务层处理
 *
 * @author zcc
 * @date 2024-11-20
 */
@RequiredArgsConstructor
@Service
public class PurchaseRequestsService {

    private final PurchaseRequestsMapper purchaseRequestsMapper;

    private final PurchaseRequestDetailsService purchaseRequestDetailsService;

    private final PurchaseRequestDetailsMapper purchaseRequestDetailsMapper;

    private final WarehouseMapper warehouseMapper;

    private final ReceiptOrderService receiptOrderService;
    private final ReceiptOrderMapper receiptOrderMapper;
    private final ReceiptOrderDetailMapper receiptOrderDetailMapper;

    /**
     * 查询采购申请
     */
    public PurchaseRequestsVo queryById(Long id) {
        PurchaseRequestsVo requestsVo = purchaseRequestsMapper.selectVoById(id);
        Assert.notNull(requestsVo, "采购申请不存在");
        requestsVo.setDetails(purchaseRequestDetailsService.queryByPurchaseId(id));
        return requestsVo;
    }

    /**
     * 查询采购申请列表
     */
    public TableDataInfo<PurchaseRequestsVo> queryPageList(PurchaseRequestsBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PurchaseRequests> lqw = buildQueryWrapper(bo);
        Page<PurchaseRequestsVo> result = purchaseRequestsMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询采购申请列表
     */
    public List<PurchaseRequestsVo> queryList(PurchaseRequestsBo bo) {
        LambdaQueryWrapper<PurchaseRequests> lqw = buildQueryWrapper(bo);
        return purchaseRequestsMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PurchaseRequests> buildQueryWrapper(PurchaseRequestsBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PurchaseRequests> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getRequestNumber()), PurchaseRequests::getRequestNumber, bo.getRequestNumber());
        lqw.between(params.get("beginRequestDate") != null && params.get("endRequestDate") != null,
            PurchaseRequests::getRequestDate, params.get("beginRequestDate"), params.get("endRequestDate"));
        lqw.between(params.get("beginExpectedDeliveryDate") != null && params.get("endExpectedDeliveryDate") != null,
            PurchaseRequests::getExpectedDeliveryDate, params.get("beginExpectedDeliveryDate"), params.get("endExpectedDeliveryDate"));
        lqw.eq(bo.getPurchaseStatus() != null, PurchaseRequests::getPurchaseStatus, bo.getPurchaseStatus());
        return lqw;
    }

    /**
     * 获取首字母
     *
     * @param str
     * @return
     */
    public static String getPinYinHeadChar(String str) {
        if (str == null || str.trim().equals("")) {
            return "";
        }
        String convert = "";
        for (int j = 0; j < str.length(); j++) {
            char word = str.charAt(j);
            // 提取字符的首字母
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
            if (pinyinArray != null) {
                convert += pinyinArray[0].charAt(0);
            } else {
                convert += word;
            }
        }
//        去除字符中包含的空格
//        convert = convert.replace(" ","");
//        字符转小写
//        convert.toLowerCase();
        return convert.toUpperCase();
    }

    /**
     * 暂存采购申请
     */
    @Transactional
    public void insertByBo(PurchaseRequestsBo bo) {
        //1.校验采购单号的唯一性
        validatePurchaseOrderNo(bo.getRequestNumber());
        //2.创建采购申请单
        if (bo.getRequestNumber() == null) {
            //自定义规则生成采购订单号 仓库名采购日期+6位随机数
            WarehouseVo warehouseVo = warehouseMapper.selectVoById(bo.getWarehouseId());
            String now = DateUtils.dateTimeNow("yyyyMMdd");
            //去除-
            now = now.replace("-", "").replace(":", "");
            String requestNumber = getPinYinHeadChar(warehouseVo.getWarehouseName()).substring(0, 2) + now + RandomStringUtils.randomNumeric(6).trim();
            //拼接
            bo.setRequestNumber(requestNumber);
        }
        PurchaseRequests add = MapstructUtils.convert(bo, PurchaseRequests.class);
        purchaseRequestsMapper.insert(add);
        //3.创建采购申请单明细
        List<PurchaseRequestDetailsBo> detailsBos = bo.getPurchaseRequestsDetails();
        List<PurchaseRequestDetails> addDetailList = MapstructUtils.convert(detailsBos, PurchaseRequestDetails.class);
        if (addDetailList != null) {
            addDetailList.forEach(it -> {
                it.setRequestId(add.getId());
                it.setAmount(it.getPrice().multiply(it.getQuantity()));
            });
        }
        purchaseRequestDetailsService.saveDetails(addDetailList);
        List<PurchaseRequestDetails> detailsList = purchaseRequestDetailsMapper.selectList(Wrappers.<PurchaseRequestDetails>lambdaQuery()
            .eq(PurchaseRequestDetails::getRequestId, add.getId()));
        //4.计算总金额
        AtomicReference<BigDecimal> totalAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> totalQuantity = new AtomicReference<>(BigDecimal.ZERO);

        for (PurchaseRequestDetails details : detailsList) {
            BigDecimal amount = details.getAmount();
            BigDecimal quantity = details.getQuantity();
            totalAmount.updateAndGet(v -> v.add(amount));
            totalQuantity.updateAndGet(v -> v.add(quantity));
        }
        //5.更新总金额
        add.setTotalQuantity(totalQuantity.get());
        add.setPayableAmount(totalAmount.get());
        purchaseRequestsMapper.updateById(add);

    }

    /**
     * 校验采购单号的唯一性
     *
     * @param requestNumber
     */
    private void validatePurchaseOrderNo(String requestNumber) {
        LambdaQueryWrapper<PurchaseRequests> lqw = Wrappers.lambdaQuery();
        lqw.eq(PurchaseRequests::getRequestNumber, requestNumber);
        if (purchaseRequestsMapper.selectCount(lqw) > 0) {
            throw new ServiceException("采购单号【" + requestNumber + "】已存在，请重新输入！", HttpStatus.CONFLICT.value());
        }
    }

    /**
     * 修改采购申请
     */
    public void updateByBo(PurchaseRequestsBo bo) {
        PurchaseRequests update = MapstructUtils.convert(bo, PurchaseRequests.class);
        purchaseRequestsMapper.updateById(update);
        //保存采购详情明细
        if (bo.getPurchaseRequestsDetails().isEmpty() && bo.getPurchaseRequestsDetails() == null) {
            throw new ServiceException("采购详情不能为空！", HttpStatus.CONFLICT.value());
        }
        List<PurchaseRequestDetails> detailsList = MapstructUtils.convert(bo.getPurchaseRequestsDetails(), PurchaseRequestDetails.class);
        detailsList.forEach(it -> {
            it.setRequestId(update.getId());
        });
        purchaseRequestDetailsService.saveDetails(detailsList);
    }


    /**
     * 删除采购申请单
     *
     * @param id
     */
    public void deleteById(@NotEmpty(message = "主键不能为空") Long id) {
        validateIdBeforeDelete(id);
        purchaseRequestsMapper.deleteById(id);
    }

    /**
     * @param id
     */
    private void validateIdBeforeDelete(Long id) {
        //采购申请详情里面不能为空
        PurchaseRequestsVo requestsVo = queryById(id);
        Assert.notNull(requestsVo, "采购申请不存在");
        if (PurchaseStatusEnum.SUCCESS.getValue() == requestsVo.getPurchaseStatus()) {
            throw new ServiceException("该采购订单【" + requestsVo.getRequestNumber() + "】已入库，无法删除！", HttpStatus.CONFLICT.value());
        }
    }

    /**
     * 审核采购申请接口
     *
     * @param id
     */
    public Boolean audit(Long id) {
        //1.校验采购申请是否存在
        PurchaseRequests requests = purchaseRequestsMapper.selectById(id);
        if (requests == null) {
            throw new ServiceException("采购申请不存在", HttpStatus.NOT_FOUND.value());
        }
        //2.校验采购申请是否为暂存状态
        if (requests.getPurchaseStatus() != PurchaseStatusEnum.WAIT.getValue()) {
            throw new ServiceException("该采购申请【" + requests.getRequestNumber() + "】已审核，请勿重复审核！", HttpStatus.CONFLICT.value());
        }
        //3.修改采购申请状态
        requests.setPurchaseStatus(PurchaseStatusEnum.AUDIT.getValue());
        PurchaseRequestsVo requestsVo = queryById(id);
        List<PurchaseRequestDetailsVo> requestDetailsVos = requestsVo.getDetails();
        if (CollectionUtil.isEmpty(requestDetailsVos)) {
            throw new ServiceException("采购申请详情不能为空", HttpStatus.CONFLICT.value());
        }
        ReceiptOrderBo bo = insertReceiptOrder(requestsVo, requestDetailsVos);
        receiptOrderService.insertByBo(bo);
        //保存
        purchaseRequestsMapper.updateById(requests);
        return true;
    }

    /**
     * 审核成功，暂存入库单
     *
     * @param requestsVo
     * @param requestDetailsVos
     */
    private ReceiptOrderBo insertReceiptOrder(PurchaseRequestsVo requestsVo, List<PurchaseRequestDetailsVo> requestDetailsVos) {
        //4.调用暂存入库单
        ReceiptOrderBo bo = new ReceiptOrderBo();
        bo.setAreaId(requestsVo.getAreaId());
        bo.setOrderNo(requestsVo.getRequestNumber());
        bo.setRemark(requestsVo.getRemark());
        bo.setWarehouseId(requestsVo.getWarehouseId());
        bo.setPayableAmount(requestsVo.getPayableAmount());
        bo.setMerchantId(requestsVo.getMerchantId());
        bo.setReceiptOrderStatus(ServiceConstants.ReceiptOrderStatus.PENDING);
        bo.setReceiptOrderType((long) ReceiptTypeEnum.PURCHASE.getValue());
        bo.setTotalQuantity(requestsVo.getTotalQuantity());
        bo.setReceiptOrderNo("RK" + RandomUtil.randomNumbers(8));
        bo.setCreateBy(LoginHelper.getUsername());
        bo.setUpdateBy(LoginHelper.getUsername());
        List<ReceiptOrderDetailBo> detailBos = new ArrayList<>();
        for (PurchaseRequestDetailsVo requestDetailsVo : requestDetailsVos) {
            ReceiptOrderDetailBo detailBo = getDetailBo(requestsVo, requestDetailsVo);
            detailBos.add(detailBo);
        }
        bo.setDetails(detailBos);
        return bo;
    }

    /**
     * 根据采购申请详情获取入库单详情
     *
     * @param requestsVo
     * @param requestDetailsVo
     * @return
     */
    @NotNull
    private static ReceiptOrderDetailBo getDetailBo(PurchaseRequestsVo requestsVo, PurchaseRequestDetailsVo requestDetailsVo) {
        ReceiptOrderDetailBo detailBo = new ReceiptOrderDetailBo();
        detailBo.setRemark(requestDetailsVo.getRemark());
        detailBo.setSkuId(requestDetailsVo.getSkuId());
        detailBo.setWarehouseId(requestsVo.getWarehouseId());
        detailBo.setAreaId(requestsVo.getAreaId());
        detailBo.setQuantity(requestDetailsVo.getQuantity());
        detailBo.setAmount(requestDetailsVo.getAmount());
//        detailBo.setCreateBy(LoginHelper.getUsername());
//        detailBo.setUpdateBy(LoginHelper.getUsername());
        return detailBo;
    }

    /**
     * 采购申请入库
     *
     * @param id
     * @return
     */
    public Boolean inbound(Long id) {
        //1.校验采购申请是否存在
        PurchaseRequests requests = purchaseRequestsMapper.selectById(id);
        if (requests == null) {
            throw new ServiceException("采购申请不存在", HttpStatus.NOT_FOUND.value());
        }
        //2.校验采购申请是否为审核状态
        String requestNumber = requests.getRequestNumber();
        if (requests.getPurchaseStatus() != PurchaseStatusEnum.AUDIT.getValue()) {
            throw new ServiceException("该采购申请【" + requestNumber + "】已入库，请勿重复入库！", HttpStatus.CONFLICT.value());
        }
        //3.修改采购申请状态
        requests.setPurchaseStatus(PurchaseStatusEnum.SUCCESS.getValue());
        PurchaseRequestsVo requestsVo = queryById(id);
        List<PurchaseRequestDetailsVo> requestDetailsVos = requestsVo.getDetails();
        if (CollectionUtil.isEmpty(requestDetailsVos)) {
            throw new ServiceException("采购申请详情不能为空", HttpStatus.CONFLICT.value());
        }
        ReceiptOrder receiptOrder = receiptOrderMapper.selectOne(Wrappers.<ReceiptOrder>lambdaQuery()
            .eq(ReceiptOrder::getOrderNo, requestNumber));
        if (receiptOrder == null) {
            throw new ServiceException("入库单不存在", HttpStatus.NOT_FOUND.value());
        }
        Long receiptOrderId = receiptOrder.getId();
        List<ReceiptOrderDetail> detailsList = receiptOrderDetailMapper.selectList(Wrappers.<ReceiptOrderDetail>lambdaQuery()
            .eq(ReceiptOrderDetail::getReceiptOrderId, receiptOrderId));
        ReceiptOrderBo bo = insertReceiptOrder(requestsVo, requestDetailsVos);
        bo.setId(receiptOrderId);
        bo.setReceiptOrderStatus(ServiceConstants.ReceiptOrderStatus.FINISH);
        //设置采购订单详情的id
        for (int i = 0; i < detailsList.size(); i++) {
            bo.getDetails().get(i).setId(detailsList.get(i).getId());
        }
        //4.采购申请单入库
        receiptOrderService.receive(bo);
        //保存
        purchaseRequestsMapper.updateById(requests);
        return true;
    }


    /**
     * 根据时间范围查询
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public PurchaseStatisticsVo statistics(String beginDate, String endDate) {
        List<LocalDate> dateList = new ArrayList<>();
        LocalDate begin = LocalDate.parse(beginDate);
        LocalDate end = LocalDate.parse(endDate);
        dateList.add(begin);
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            //日期计算，获得指定日期后1天的日期
            dateList.add(begin);
        }
        List<Long> countList = new ArrayList<>();
        List<BigDecimal> amountList = new ArrayList<>();
        for (LocalDate date : dateList) {
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            Map map = new HashMap();
            map.put("purchase_status", PurchaseStatusEnum.SUCCESS.getValue());
            map.put("begin", beginTime);
            map.put("end", endTime);
            PurchaseStatisics sumByMap = purchaseRequestsMapper.sumByMap(map);
            if (sumByMap != null) {
                countList.add(sumByMap.getTotal());
                amountList.add(sumByMap.getTotalAmount());
            } else {
                countList.add(0L);
                amountList.add(BigDecimal.ZERO);
            }
        }
        PurchaseStatisticsVo vo = new PurchaseStatisticsVo();
        vo.setDateList(StringUtils.join(dateList, ","));
        vo.setPurchaseRequestCount(StringUtils.join(countList, ","));
        vo.setAmountList(StringUtils.join(amountList, ","));
        return vo;
    }
}
